﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Globalization;
using RapidSpider.Enumerators;
using RapidSpider.DownloadAgents;
using RapidSpider.Views;
using System.Drawing;

namespace RapidSpider.ApplicationControllers
{
    public partial class Controller : IDisposable
    {
        #region Members
        private Object _LockObject = new Object();
        private int _ActiveInitialiseCount;
        private int _ActiveDownloadCount;
        #endregion

        #region Properties
        public int ActiveDownloadCount
        {
            get
            {
                lock (this._LockObject)
                {
                    int theActiveDownloadCount = 0;

                    for (int i = 0; i < this._MainView.gridDownloads.Rows.Count; i++)
                    {
                        IDownloadAgent thisAgent =
                            this._MainView.gridDownloads.Rows[i].Tag as
                                IDownloadAgent;

                        if (null != thisAgent)
                        {
                            if (thisAgent.Status.Equals(DownloadAgentStatus.Starting) ||
                                thisAgent.Status.Equals(DownloadAgentStatus.Downloading))
                            {
                                ++theActiveDownloadCount;
                            }
                        }
                    }

                    return theActiveDownloadCount;
                }
            }
        }
        #endregion

        #region Methods
        public bool InitialiseDownload(IDownloadAgent theAgent)
        {
            if (null != theAgent)
            {
                lock (this._LockObject)
                {
                    if (this._ActiveInitialiseCount < RegistryAgent.ConcurrentDownloads &&
                        (theAgent.Status.Equals(DownloadAgentStatus.NotStarted) ||
                        theAgent.Status.Equals(DownloadAgentStatus.TimedOut)))
                    {
                        Thread thisThread = new Thread(new ThreadStart(theAgent.Initialise));
                        thisThread.Name = theAgent.GetHashCode().ToString(
                            CultureInfo.CurrentCulture);

                        Controller.Threads.Add(thisThread);

                        ++this._ActiveInitialiseCount;

                        thisThread.Start();
                        return true;
                    }
                }
            }
            return false;
        }

        public bool StartDownload(IDownloadAgent theAgent)
        {
            if (null != theAgent)
            {
                lock (this._LockObject)
                {
                    if (this._ActiveDownloadCount < RegistryAgent.ConcurrentDownloads &&
                        (theAgent.Status.Equals(DownloadAgentStatus.Initialised) ||
                        theAgent.Status.Equals(DownloadAgentStatus.Paused)))
                    {
                        Thread thisThread = new Thread(new ThreadStart(theAgent.Start));
                        thisThread.Name = theAgent.GetHashCode().ToString(
                            CultureInfo.CurrentCulture);

                        Controller.Threads.Add(thisThread);

                        ++this._ActiveDownloadCount;

                        thisThread.Start();
                        return true;
                    }
                }
            }
            return false;
        }
        
        #region Event Handlers
        private void DownloadAgent_StatusChanged(
            object sender,
            EventArgs e)
        {
            Application.DoEvents();

            IDownloadAgent theInstance = sender as IDownloadAgent;

            for (int i = 0; i < this._MainView.gridDownloads.Rows.Count; i++)
            {
                if (this._MainView.gridDownloads.Rows[i].Tag.Equals(theInstance))
                {
                    switch (theInstance.Status)
                    {
                        case DownloadAgentStatus.Initialising:
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                "Initialising...";
                            break;
                        case DownloadAgentStatus.Initialised:
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_SIZE].Value =
                                String.Format(
                                    CultureInfo.CurrentCulture,
                                    "{0}Mb",
                                    theInstance.SourceFileSize);

                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_SERVER].Value =
                                theInstance.SourceServer;

                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                theInstance.DownloadedAmount > 0
                                ? "Set to Resume"
                                : "Ready";
                            break;
                        case DownloadAgentStatus.Starting:
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                "Starting...";
                            break;
                        case DownloadAgentStatus.Downloading:
                            if (theInstance.TargetFileSize > 0)
                            {
                                this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_SPEED].Value =
                                    String.Format(
                                        CultureInfo.CurrentCulture,
                                        "{0} Kbps",
                                        theInstance.DownloadSpeed);

                                this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_PROGRESS].Value =
                                    String.Format(
                                        CultureInfo.CurrentCulture,
                                        "{0}%",
                                        theInstance.DownloadedPercentage);

                                double theRed = theInstance.DownloadedPercentage < 50
                                    ? 255
                                    : 255 - (255.0 / 100 * ((theInstance.DownloadedPercentage - 50) * 2));
                                double theGreen = theInstance.DownloadedPercentage < 50
                                    ? 255.0 / 100 * (theInstance.DownloadedPercentage * 2)
                                    : 255;

                                this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_PROGRESS].Style.BackColor =
                                    Color.FromArgb((byte)theRed, (byte)theGreen, 0);

                                Application.DoEvents();
                            }

                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                String.Format(
                                    CultureInfo.CurrentCulture,
                                    "{0}Mb Remaining",
                                    theInstance.RemainingAmount);
                            break;
                        case DownloadAgentStatus.Paused:
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                "Paused";
                            break;
                        case DownloadAgentStatus.Cancelled:
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                "Cancelled"; 
                            break;
                        case DownloadAgentStatus.TimedOut:
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                "Timeout";
                            break;
                        case DownloadAgentStatus.LimitExceeded:
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                "Download limit exceeded";
                            break;
                        case DownloadAgentStatus.FileDeleted:
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                "File has been deleted from server";
                            break;
                        case DownloadAgentStatus.FileNotFound:
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                "File not found";
                            break;
                        case DownloadAgentStatus.PremiumAccountExpired:
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                "Premium account expired";
                            break;
                        case DownloadAgentStatus.FileGreaterThan100Mb:
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                "File greater than 100Mb";
                            break;
                        case DownloadAgentStatus.ServerUnavailable:
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                "Server unavailable";
                            break;
                        default:
                            if (theInstance.TargetFileSize > 0)
                            {
                                this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_PROGRESS].Value = 
                                    "0%";
                            }
                            this._MainView.gridDownloads.Rows[i].Cells[MainView.COLUMN_INDEX_STATUS].Value =
                                theInstance.StatusMessage;
                            break;
                    }
                    break;
                }
            }
        }

        private void DownloadAgent_Initialising(
            object sender,
            EventArgs e)
        {
            IDownloadAgent theInstance =
                sender as IDownloadAgent;

            this.AppendLogFile(
                theInstance.Status.ToString(),
                theInstance.SourceUri.ToString());

            this.UpdateStatusBar();
        }

        private void DownloadAgent_Initialised(
            object sender,
            EventArgs e)
        {
            IDownloadAgent theInstance =
                sender as IDownloadAgent;

            Controller.AbortAndRemoveThread(theInstance);

            this.AppendLogFile(
                theInstance.Status.ToString(),
                theInstance.SourceUri.ToString());

            lock (this._LockObject)
            {
                --this._ActiveInitialiseCount;
            }
            
            this.UpdateReinitialiseButton(theInstance);

            this.InitialiseAll();

            this.UpdateStatusBar();
        }
        
        private void DownloadAgent_Starting(
            object sender,
            EventArgs e)
        {
            IDownloadAgent theInstance =
                sender as IDownloadAgent;

            this.AppendLogFile(
                theInstance.Status.ToString(),
                theInstance.SourceUri.ToString());

            this.UpdateStatusBar();
        }

        private void DownloadAgent_Downloading(
            object sender,
            EventArgs e)
        {
            this.UpdateStatusBar();
        }

        private void DownloadAgent_Paused(
            object sender,
            EventArgs e)
        {
            IDownloadAgent theInstance =
                sender as IDownloadAgent;

            Controller.AbortAndRemoveThread(theInstance);

            this.AppendLogFile(
                theInstance.Status.ToString(),
                theInstance.SourceUri.ToString());

            lock (this._LockObject)
            {
                --this._ActiveDownloadCount;
            } 
            
            this.UpdateStatusBar();
        }

        private void DownloadAgent_Completed(
            object sender,
            EventArgs e)
        {
            IDownloadAgent theInstance =
                sender as IDownloadAgent;

            Controller.AbortAndRemoveThread(theInstance);

            this._MainView.RemoveRow(theInstance);

            this.AppendLogFile(
                theInstance.Status.ToString(), 
                theInstance.SourceUri.ToString());

            lock (this._LockObject)
            {
                --this._ActiveDownloadCount;
            }

            this.UpdateStatusBar();

            if (this._MainView.Status.Equals(MainViewStatus.Started))
            {
                this.PlayAll();
            }
        }

        private void DownloadAgent_Cancelled(
            object sender,
            EventArgs e)
        {
            IDownloadAgent theInstance =
                sender as IDownloadAgent;

            Controller.AbortAndRemoveThread(theInstance);

            this.AppendLogFile(
                theInstance.Status.ToString(),
                theInstance.SourceUri.ToString());

            lock (this._LockObject)
            {
                --this._ActiveDownloadCount;
            }

            this.UpdateStatusBar();

            if (this._MainView.Status.Equals(MainViewStatus.Started))
            {
                this.PlayAll();
            }
        }

        private void DownloadAgent_Failed(
            object sender,
            EventArgs e)
        {
            IDownloadAgent theInstance =
                sender as IDownloadAgent;

            Controller.AbortAndRemoveThread(theInstance);

            this.AppendLogFile(
                theInstance.Status.ToString(),
                theInstance.SourceUri.ToString());

            lock (this._LockObject)
            {
                --this._ActiveDownloadCount;
            }

            this.UpdateStatusBar();

            if (this._MainView.Status.Equals(MainViewStatus.Started))
            {
                this.PlayAll();
            }
        }
        #endregion
        #endregion
    }
}
